package optimizers;

import weka.core.Instances;
import data_structures.ConfigurationAccuracyPair;
import java.util.PriorityQueue;
import java.util.ArrayList;

import classifiers.Classifier;
import data_structures.HPConfiguration;

/**
 * Brute-force optimization for hyper-parameter configurations. It is the
 * base-line approach which can be used for comparison.
 */
public class BruteForceHPOptimizer implements HPOptimizer {
	private Instances entireData;
	private Classifier classifier;
	private ArrayList<HPConfiguration> configurations;
	private int topK;

	/**
	 * @param entireData
	 *            Entire data-set that the classifier will be tested on.
	 * @param classifier
	 *            The classifier that is used for classification.
	 * @param configurations
	 *            List of configurations to try. It is generally the
	 *            configuration space. If there are continious hyper-parameters
	 *            then we need to discretize somehow to get this list of
	 *            configurations.
	 * @param topK
	 *            The size of the heap that will be returned by the
	 *            <code>optimize</code> method.
	 */
	public BruteForceHPOptimizer(Instances entireData, Classifier classifier,
			ArrayList<HPConfiguration> configurations, int topK) {
		this.entireData = entireData;
		this.classifier = classifier;
		this.configurations = configurations;
		this.topK = topK;
	}

	/**
	 * Tries every configuration given in the constructor and return top-k of
	 * them.
	 */
	public PriorityQueue<ConfigurationAccuracyPair> optimize() {
		PriorityQueue<ConfigurationAccuracyPair> topKConfigurations = new PriorityQueue<ConfigurationAccuracyPair>();

		for (HPConfiguration configuration : configurations) {
			double acc = classifier.evaluateClassifier(entireData,
					configuration);

			topKConfigurations.add(new ConfigurationAccuracyPair(configuration,
					acc));

			if (topKConfigurations.size() > topK) {
				topKConfigurations.poll();
			}
		}

		return topKConfigurations;
	}
}
